module Evaluator where

import qualified Data.Map as M
import Data.Map((!))

import Control.Monad.State
import Control.Monad.Error

data Value = VI !Int | VF !Card

data Card = I Value | Zero | Succ Value | Dbl Value |
            Get Value | Put Value |
            S Value Value Value | K Value Value | Inc Value | Dec Value |
            Attack Value Value Value | Help Value Value Value | Copy Value | Revive Value | Zombie Value

newtype PlayerState = PS {unPS :: M.Map Int (Int, Value)}

init_player_state = PS $ M.fromList $ zip [0..255] (repeat (10000, VF $ I (error "I's init fake arg")))

data GameState = GS {proponent :: PlayerState, opponent :: PlayerState}

init_game_state = GS init_player_state init_player_state

type Game a = StateT GameState (Either String) a

runGame gs g = runStateT gs g

eval :: Value -> Game Value
eval (VF (I v)) = return v
eval (VF Zero) = return $ VI 0
eval (VF (Succ v)) = do v' <- eval v
                        if_int v' (\i -> VI $ min 65535 (i+1)) "can't apply Succ to function"

eval (VF (Get v)) = do
  v' <- eval v
  ps <- gets proponent

  i <- inside v' 0 255
  let (vit, val) = (unPS ps) ! i
  if vit > 0 then return val
   else throwError "can't get dead slot"

if_int v c e  = case v of
                  VI i -> return $ c i
                  _ -> throwError e

inside v a b = case v of
                 VI i -> if a <= i && i <= b then return i else throwError "value is out of range"
                 _ -> throwError "not a value"
